#include "dispatcher_commands.h"
#include "core/dispatcher.h"
#include "core/value.h"
#include "core/inspector.h"
#include "idispatchable.h"

using namespace Commands;
using namespace Commands::Core;

using namespace Commands;

//-----------------------------------------------------------------------------
SetData::SetData()
: Command<Dispatcher>(0l)
, dataId(-1)
, value(new Value())
, queueId(-1)
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
SetData::SetData(int dataId, float value)
: Command<Dispatcher>(0l)
, dataId(dataId)
, value(new Value(value))
, queueId(-1)
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
SetData::SetData(int dataId, const Value& value)
: Command<Dispatcher>(0l)
, dataId(dataId)
, value(value.Copy())
, queueId(-1)
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
SetData::SetData(int queueId, int dataId, float value)
: Command<Dispatcher>(0l)
, dataId(dataId)
, value(new Value(value))
, queueId(queueId)
, queueDefined(true)
{}
//-----------------------------------------------------------------------------
SetData::SetData(int queueId, int dataId, const Value& value)
: Command<Dispatcher>(0l)
, dataId(dataId)
, value(value.Copy())
, queueId(queueId)
, queueDefined(true)
{}
//-----------------------------------------------------------------------------
float SetData::Execute(const float seconds)
{
    const float consumedSeconds = value->Execute(seconds);
    if(Dispatcher* dispatcher = GetObject())
    {
        dispatcher->SetData(dataId, value->GetValue());
    }
    return consumedSeconds;
}
//-----------------------------------------------------------------------------
bool SetData::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
SetData::~SetData()
{
    delete value;
}
//-----------------------------------------------------------------------------
SetData* SetData::Copy(void) const
{
    if(queueDefined)
    {
        return new SetData(queueId, dataId, *value);
    }

    return new SetData(dataId, *value);
}
//-----------------------------------------------------------------------------
void SetData::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
Wait::Wait()
: Command<Dispatcher>(0l)
, waitTime(0)
, elapsedTime(0.0f)
, isFirstCall(true)
, isFinished(false)
{}
//-----------------------------------------------------------------------------
Wait::Wait(float time)
: Command<Dispatcher>(0l)
, waitTime(time)
, elapsedTime(0.0f)
, isFirstCall(true)
, isFinished(false)
{}
//-----------------------------------------------------------------------------
float Wait::Execute(const float seconds)
{
    if(isFirstCall)
    {
        elapsedTime = 0.0f;
        isFirstCall = false;
        isFinished = false;
    }

    if((elapsedTime + seconds) >= waitTime)
    {
        isFinished = true;
        isFirstCall = true;
        return waitTime - elapsedTime;
    }
    else
    {
        elapsedTime += seconds;
        return seconds;
    }
}
//-----------------------------------------------------------------------------
bool Wait::IsFinished(void) const
{
    return isFinished;
}
//-----------------------------------------------------------------------------
Wait::~Wait()
{}
//-----------------------------------------------------------------------------
Wait* Wait::Copy(void) const
{
    return new Wait(waitTime);
}
//-----------------------------------------------------------------------------
void Wait::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
Clear::Clear()
: Command<Dispatcher>(0l)
, queue(-1)
{}
//-----------------------------------------------------------------------------
Clear::Clear(int queue)
: Command<Dispatcher>(0l)
, queue(queue)
{}
//-----------------------------------------------------------------------------
float Clear::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        if(queue == -1)
        {
            dispatcher->DefferedClear();
        }
        else
        {
            dispatcher->DefferedClear(queue);
        }
    }
    return 0.0;
}
//-----------------------------------------------------------------------------
bool Clear::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
Clear::~Clear()
{}
//-----------------------------------------------------------------------------
Clear* Clear::Copy(void) const
{
    return new Clear(queue);
}
//-----------------------------------------------------------------------------
void Clear::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
GoToCommand::GoToCommand()
: Command<Dispatcher>(0l)
, commandIdx(0)
, queueId(-1)
, condition(new False())
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
GoToCommand::GoToCommand(size_t commandIdx)
: Command<Dispatcher>(0l)
, commandIdx(commandIdx)
, queueId(-1)
, condition(new True())
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
GoToCommand::GoToCommand(size_t commandIdx, const Condition& condition)
: Command<Dispatcher>(0l)
, commandIdx(commandIdx)
, queueId(-1)
, condition(condition.Copy())
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
GoToCommand::GoToCommand(size_t commandIdx, int queueId)
: Command<Dispatcher>(0l)
, commandIdx(commandIdx)
, queueId(queueId)
, condition(new True())
, queueDefined(true)
{}
//-----------------------------------------------------------------------------
GoToCommand::GoToCommand(size_t commandIdx, int queueId, const Condition& condition)
: Command<Dispatcher>(0l)
, commandIdx(commandIdx)
, queueId(queueId)
, condition(condition.Copy())
, queueDefined(true)
{}
//-----------------------------------------------------------------------------
float GoToCommand::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        if(condition->IsTrue())
        {
            if(!queueDefined)
            {
                dispatcher->GoToCommand(commandIdx);
            }
            else
            {
                dispatcher->GoToCommand(commandIdx, queueId);
            }
        }
    }
    return 0.0;
}
//-----------------------------------------------------------------------------
bool GoToCommand::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
GoToCommand::~GoToCommand()
{}
//-----------------------------------------------------------------------------
GoToCommand* GoToCommand::Copy(void) const
{
    if(queueDefined)
    {
        new GoToCommand(commandIdx, queueId, *condition);
    }

    return new GoToCommand(commandIdx, *condition);
}
//-----------------------------------------------------------------------------
void GoToCommand::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
Mark::Mark()
: Command<Dispatcher>(0l)
, mark(-1)
{}
//-----------------------------------------------------------------------------
Mark::Mark(int mark)
: Command<Dispatcher>(0l)
, mark(mark)
{}
//-----------------------------------------------------------------------------
float Mark::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        dispatcher->AddMark(mark);
    }
    return 0.0;
}
//-----------------------------------------------------------------------------
bool Mark::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
Mark::~Mark()
{}
//-----------------------------------------------------------------------------
Mark* Mark::Copy(void) const
{
    return new Mark(mark);
}
//-----------------------------------------------------------------------------
void Mark::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
GoToMark::GoToMark()
: Command<Dispatcher>(0l)
, mark(-1)
, queueId(-1)
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
GoToMark::GoToMark(int mark)
: Command<Dispatcher>(0l)
, mark(mark)
, queueId(-1)
, queueDefined(false)
{}
//-----------------------------------------------------------------------------
GoToMark::GoToMark(int mark, int queueId)
: Command<Dispatcher>(0l)
, mark(mark)
, queueId(queueId)
, queueDefined(true)
{}
//-----------------------------------------------------------------------------
float GoToMark::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        if(!queueDefined)
        {
            dispatcher->GoToMarkedCommand(mark);
        }
        else
        {
            dispatcher->GoToMarkedCommand(mark, queueId);
        }
    }
    return 0.0;
}
//-----------------------------------------------------------------------------
bool GoToMark::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
GoToMark::~GoToMark()
{}
//-----------------------------------------------------------------------------
GoToMark* GoToMark::Copy(void) const
{
    if(queueDefined)
    {
        return new GoToMark(mark, queueId);
    }

    return new GoToMark(mark);
}
//-----------------------------------------------------------------------------
void GoToMark::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
LoopToMark::LoopToMark()
: Command<Dispatcher>(0l)
, mark(-1)
, times(0)
, loopCounter(0)
{}
//-----------------------------------------------------------------------------
LoopToMark::LoopToMark(int mark, unsigned int times)
: Command<Dispatcher>(0l)
, mark(mark)
, times(times)
, loopCounter(0)
{}
//-----------------------------------------------------------------------------
float LoopToMark::Execute(const float)
{
    if(loopCounter < times)
    {
        if(Dispatcher* dispatcher = GetObject())
        {
            dispatcher->GoToMarkedCommand(mark);
        }
        loopCounter++;
    }
    else
    {
        loopCounter = 0;
    }

    return 0.0;
}
//-----------------------------------------------------------------------------
bool LoopToMark::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
LoopToMark::~LoopToMark()
{}
//-----------------------------------------------------------------------------
LoopToMark* LoopToMark::Copy(void) const
{
    return new LoopToMark(mark, times);
}
//-----------------------------------------------------------------------------
void LoopToMark::Accept(Core::Inspector& inspector)
{
    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
PermitQueue::PermitQueue(int queueId)
: queueId(queueId)
{}
//-----------------------------------------------------------------------------
PermitQueue::~PermitQueue()
{}
//-----------------------------------------------------------------------------
void PermitQueue::Accept(Core::Inspector& inspector)
{}
//-----------------------------------------------------------------------------
PermitQueue* PermitQueue::Copy(void) const
{
    return new PermitQueue(queueId);
}
//-----------------------------------------------------------------------------
float PermitQueue::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        dispatcher->PermitQueue(queueId);
    }
    return 0.0f;
}
//-----------------------------------------------------------------------------
bool PermitQueue::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
ForbidQueue::ForbidQueue(int queueId)
: queueId(queueId)
{}
//-----------------------------------------------------------------------------
ForbidQueue::~ForbidQueue()
{}
//-----------------------------------------------------------------------------
void ForbidQueue::Accept(Core::Inspector& inspector)
{}
//-----------------------------------------------------------------------------
ForbidQueue* ForbidQueue::Copy(void) const
{
    return new ForbidQueue(queueId);
}
//-----------------------------------------------------------------------------
float ForbidQueue::Execute(const float)
{
    if(Dispatcher* dispatcher = GetObject())
    {
        dispatcher->ForbidQueue(queueId);
    }
    return 0.0f;
}
//-----------------------------------------------------------------------------
bool ForbidQueue::IsFinished(void) const
{
    return true;
}
//-----------------------------------------------------------------------------
WaitTillCommandsEnded::WaitTillCommandsEnded(IDispatchable* dispatchable, int queueId)
: Command<Dispatcher>(0l)
, isFirstCall(true)
, isFinished(false)
, dispatchable(dispatchable)
, queueId(queueId)
, queueDefined(true)
{
    assert(dispatchable);
}
//-----------------------------------------------------------------------------
WaitTillCommandsEnded::WaitTillCommandsEnded(IDispatchable* dispatchable)
: Command<Dispatcher>(0l)
, isFirstCall(true)
, isFinished(false)
, dispatchable(dispatchable)
, queueId(-1)
, queueDefined(false)
{
    assert(dispatchable);
}
//-----------------------------------------------------------------------------
float WaitTillCommandsEnded::Execute(const float seconds)
{
    if(isFirstCall)
    {
        isFirstCall = false;
        isFinished = false;
    }

    if(queueDefined)
    {
        if (dispatchable->CommandsEnded(queueId))
        {
            isFinished = true;
            isFirstCall = true;
            return 0;
        }
    }
    else
    {
        if (dispatchable->CommandsEnded())
        {
            isFinished = true;
            isFirstCall = true;
            return 0;
        }
    }

    return seconds;
}
//-----------------------------------------------------------------------------
bool WaitTillCommandsEnded::IsFinished(void) const
{
    return isFinished;
}
//-----------------------------------------------------------------------------
WaitTillCommandsEnded::~WaitTillCommandsEnded()
{}
//-----------------------------------------------------------------------------
WaitTillCommandsEnded* WaitTillCommandsEnded::Copy(void) const
{
    if(queueDefined)
    {
        return new WaitTillCommandsEnded(dispatchable, queueId);
    }

    return new WaitTillCommandsEnded(dispatchable);
}
//-----------------------------------------------------------------------------
void WaitTillCommandsEnded::Accept(Core::Inspector& inspector)
{
//    inspector.Inspect(*this);
}
//-----------------------------------------------------------------------------
